import { IPainter } from "./IPainter.js";
import { IRoot } from "./IRoot.js";
import { IEventMouseDown, IEventMouseMove, IEventMouseUp, IEventClick, IEventContextMenu, MOUSE_BUTTON, IEventKeyDown, IEventKeyUp, GetKeyCode } from "./IEvent.js";

class IWindow {
    constructor(window_painter) {
        // 窗口画刷
        this.m_window_painter = window_painter;
        this.m_touch_input = false; // 是否为触摸输入设备
        // 窗口大小
        this.m_window_width = 0;
        this.m_window_height = 0;

        // 下一帧的刷新视口
        this.m_refresh_viewport_x = 0;
        this.m_refresh_viewport_y = 0;
        this.m_refresh_viewport_width = 0;
        this.m_refresh_viewport_height = 0;

        // 窗口根元素
        this.m_root = new IRoot(this);
    }

    // inline methods
    GetWindowWidth() { return this.m_window_width; }
    GetWindowHeight() { return this.m_window_height; }
    GetWindowPainter() { return this.m_window_painter; }
    GetRoot() { return this.m_root; }
    GetTheme() { return this.m_theme; }

    // 鼠标事件根元素
    SetMouseEventRootElement(element) { this.m_mouse_event_root_element = element; }
    GetMouseEventRootElement() { return this.m_mouse_event_root_element; }
    // 鼠标捕获
    SetMouseCaptureElement(element) { this.m_mouse_capture_element = element; }
    GetMouseCaptureElement() { return this.m_mouse_capture_element; }
    // 鼠标按下
    SetMouseDownElement(element) { this.m_mouse_down_element = element; }
    GetMouseDownElement() { return this.m_mouse_down_element; }
    // 键盘元素
    SetKeyBoardElement(element) { this.m_keyboard_element = element; }
    GetKeyBoardElement() { return this.m_keyboard_element; }
    // 获取焦点元素
    SetFocusElement(element) { this.m_focus_element = element; }
    GetFocusElement() { return this.m_focus_element; }
    // 光标
    SetCursor(cursor) { this.m_cursor = cursor; }
    GetCursor() { return this.m_cursor; }

    // 重绘需要刷新的区域
    Render() {
        const window_painter = this.GetWindowPainter();
        const root = this.GetRoot();
        if (this.m_refresh_viewport_width === 0 || this.m_refresh_viewport_height === 0) {
            const cursor = this.GetCursor();
            if (cursor) {
                cursor.Render(window_painter);
            }
        } else {
            // 获取刷新视口
            const refresh_viewport_x = this.m_refresh_viewport_x;
            const refresh_viewport_y = this.m_refresh_viewport_y;
            const refresh_viewport_width = this.m_refresh_viewport_width;
            const refresh_viewport_height = this.m_refresh_viewport_height;
            // 重置刷新视口
            this.m_refresh_viewport_x = 0;
            this.m_refresh_viewport_y = 0;
            this.m_refresh_viewport_width = 0;
            this.m_refresh_viewport_height = 0;
            // 绘制元素
            window_painter.Save();
            window_painter.Clip(refresh_viewport_x, refresh_viewport_y, refresh_viewport_width, refresh_viewport_height);
            root.Render(window_painter);
            window_painter.Restore();
        }
    }

    // 刷新窗口的局部区域
    // 合并调用的所有局部区域获的刷新区域的最小包围盒， 也就是下一帧需要绘制的区域
    Refresh(x, y, width, height) {
        const window_width = this.m_window_width;
        const window_height = this.m_window_height;
        let min_x = x;
        let min_y = y;
        let max_x = x + width;
        let max_y = y + height;
        if (this.m_refresh_viewport_x === 0 && this.m_refresh_viewport_y === 0 && this.m_refresh_viewport_width === 0 && this.m_refresh_viewport_height === 0) {
            max_x = Math.min(max_x, window_width);
            max_y = Math.min(max_y, window_height);
            min_x = Math.max(min_x, 0);
            min_y = Math.max(min_y, 0);
        } else {
            const min_refresh_x = this.m_refresh_viewport_x;
            const min_refresh_y = this.m_refresh_viewport_y;
            const max_refresh_x = this.m_refresh_viewport_x + this.m_refresh_viewport_width;
            const max_refresh_y = this.m_refresh_viewport_y + this.m_refresh_viewport_height;
            max_x = Math.min(Math.max(max_x, max_refresh_x), window_width);
            max_y = Math.min(Math.max(max_y, max_refresh_y), window_height);
            min_x = Math.max(Math.min(min_x, min_refresh_x), 0);
            min_y = Math.max(Math.min(min_y, min_refresh_y), 0);
        }
        this.m_refresh_viewport_x = min_x;
        this.m_refresh_viewport_y = min_y;
        this.m_refresh_viewport_width = max_x - min_x;
        this.m_refresh_viewport_height = max_y - min_y;
    }

    // 窗口大小更新
    OnSize(width, height) {
        if (this.m_window_width == width || this.m_window_height == height) {
            return;
        }
        // 保存窗口大小
        this.m_window_width = width;
        this.m_window_height = height;
        // 设置刷新视口
        this.m_refresh_viewport_x = 0;
        this.m_refresh_viewport_y = 0;
        this.m_refresh_viewport_width = this.m_window_width;
        this.m_refresh_viewport_height = this.m_window_height;
        // 标记布局更新
        this.GetRoot().SetLayoutChanged(true);
    }

    OnCaptureBubbleEvent(event_name, event) {
        const target_element = event.GetTargetElement();
        const event_elements = event.GetEventElements();
        const captrue_event_name = event_name + "Capture";
        const bubble_event_name = event_name + "Bubble";
        for (let i = 0; i < event_elements.length; i++) {
            const event_element = event_elements[i];
            if (event.IsStopPropagation()) {
                return;
            }
            if (event.IsStopCapture()) {
                break;
            }
            const event_function = event_element[captrue_event_name];
            if (typeof event_function === 'function') {
                event_function.call(event_element, event);
            }
            event_element.DispatchEvent(event, true);
        }
        if (event.IsStopPropagation()) {
            return;
        }
        const event_function = target_element[event_name];
        if (typeof event_function === 'function') {
            event_function.call(target_element, event);
        }
        for (let i = event_elements.length - 1; i >= 0; i--) {
            const event_element = event_elements[i];
            if (event.IsStopPropagation()) {
                return;
            }
            if (event.IsStopBubble()) {
                break;
            }
            const event_function = event_element[bubble_event_name];
            if (typeof event_function === 'function') {
                event_function.call(event_element, event);
            }
            event_element.DispatchEvent(event, false);
        }
    }

    OnMouseDown(x, y, button) {
        // button: 0 - left, 1 - middle, 2 - right
        // console.log("OnMouseDown", x, y, button);
        this.m_mouse_down = true;
        this.m_mouse_x = x;
        this.m_mouse_y = y;
        this.m_mouse_down_x = x;
        this.m_mouse_down_y = y;
        this.m_mouse_down_timestamp = Date.now();
        this.m_mouse_button = button;
        const event = new IEventMouseDown();
        event.SetXY(this.m_mouse_x, this.m_mouse_y);
        event.SetMouseDownXY(this.m_mouse_down_x, this.m_mouse_down_y);
        event.SetButton(this.m_mouse_button);
        event.SetMouseDownTimeStamp(this.m_mouse_down_timestamp);
        if (event.IsLeftButton()) this.m_mouse_left_button_pressed = true;
        if (event.IsRightButton()) this.m_mouse_right_button_pressed = true;
        event.SetLeftButtonPressed(this.m_mouse_left_button_pressed);
        event.SetRightButtonPressed(this.m_mouse_right_button_pressed);
        const element = this.GetElementByXY(x, y, event);
        event.SetTargetElement(element);
        this.OnCaptureBubbleEvent("OnMouseDown", event)
        this.m_mouse_down_element = element;

        // Focus 处理
        const focus_element = this.GetFocusElement();
        if (focus_element !== element) {
            if (focus_element && focus_element.OnBlur) {
                focus_element.OnBlur();
            }
            if (element && element.OnFocus) {
                element.OnFocus();
            }
            this.SetFocusElement(element);
        }
    }

    OnMouseMove(x, y) {
        // 处理鼠标移动事件
        this.m_mouse_x = x;
        this.m_mouse_y = y;
        const event = new IEventMouseMove();
        event.SetXY(this.m_mouse_x, this.m_mouse_y);
        event.SetMouseDownXY(this.m_mouse_down_x, this.m_mouse_down_y);
        event.SetButton(this.m_mouse_button);
        event.SetMouseDownTimeStamp(this.m_mouse_down_timestamp);
        event.SetLeftButtonPressed(this.m_mouse_left_button_pressed);
        event.SetRightButtonPressed(this.m_mouse_right_button_pressed);
        const element = this.GetElementByXY(x, y, event);
        event.SetTargetElement(element);
        this.OnCaptureBubbleEvent("OnMouseMove", event);

        // Mouse Enter / Leave 事件处理
        const hover_elements = this.m_hover_elements || new Set();  // 旧悬浮元素集合
        const new_hover_elements = new Set(); // 新悬浮元素集合
        const event_elements = event.GetEventElements(); // 获取事件元素列表即新悬浮元素列表
        for (let i = 0; i < event_elements.length; i++) {
            const event_element = event_elements[i];
            if (!hover_elements.has(event_element)) {
                event_element.OnMouseEnter();
                event_element.SetHover(true); // :hover 选择器会使用
            }
            new_hover_elements.add(event_element);
        }

        hover_elements.forEach((hover_element) => {
            if (!new_hover_elements.has(hover_element)) {
                hover_element.OnMouseLeave();
                hover_element.SetHover(false);
            }
        });
        this.m_hover_elements = new_hover_elements;
    }

    OnMouseUp(x, y, button) {
        // button: 0 - left, 1 - middle, 2 - right
        this.m_mouse_down = false;
        this.m_mouse_x = x;
        this.m_mouse_y = y;
        this.m_mouse_button = button;
        const event = new IEventMouseUp();
        event.SetXY(this.m_mouse_x, this.m_mouse_y);
        event.SetMouseDownXY(this.m_mouse_down_x, this.m_mouse_down_y);
        event.SetButton(this.m_mouse_button);
        event.SetMouseDownTimeStamp(this.m_mouse_down_timestamp);
        if (event.IsLeftButton()) this.m_mouse_left_button_pressed = false;
        if (event.IsRightButton()) this.m_mouse_right_button_pressed = false;
        event.SetLeftButtonPressed(this.m_mouse_left_button_pressed);
        event.SetRightButtonPressed(this.m_mouse_right_button_pressed);
        const element = this.GetElementByXY(x, y, event);
        event.SetTargetElement(element);
        this.OnCaptureBubbleEvent("OnMouseUp", event);
        this.m_mouse_up_element = element;

        if (this.m_mouse_down_element === this.m_mouse_up_element) {
            const e = button == MOUSE_BUTTON.RIGHT ? new IEventContextMenu() : new IEventClick();
            e.SetXY(this.m_mouse_x, this.m_mouse_y);
            e.SetMouseDownXY(this.m_mouse_down_x, this.m_mouse_down_y);
            e.SetButton(this.m_mouse_button);
            e.SetTargetElement(element);
            e.SetEventElements(event.GetEventElements());
            if (button == MOUSE_BUTTON.RIGHT) {
                this.OnCaptureBubbleEvent("OnContextMenu", e);
            } else {
                this.OnCaptureBubbleEvent("OnClick", e);
            }
        }

        // this.m_start_text_input = !this.m_start_text_input;
        // console.log("====StartTextInput===", this.m_start_text_input);
        // if (this.m_start_text_input) {
        //     this.StartTextInput();
        // }
    }

    OnMouseWheel(delta) {
        // delta: positive - scroll up, negative - scroll down
        const event = new IEventMouseWheel();
        event.SetXY(this.m_mouse_x, this.m_mouse_y);
        event.SetMouseDownXY(this.m_mouse_down_x, this.m_mouse_down_y);
        event.SetButton(this.m_mouse_button);
        event.SetMouseDownTimeStamp(this.m_mouse_down_timestamp);
        event.SetDelta(delta);
        const element = this.GetElementByXY(this.m_mouse_x, this.m_mouse_y, event);
        event.SetTargetElement(element);
        this.OnCaptureBubbleEvent("OnMouseWheel", event);
    }

    OnKeyDown(key) {
        // key: e.g., 'a', 'Enter', 'ArrowUp', etc.
        // console.log("OnKeyDown", key);
        const event = new IEventKeyDown(key);
        const focus_element = this.GetFocusElement();

        if (event.IsCtrl()) this.m_ctrl_pressed = true;
        if (event.IsShift()) this.m_shift_pressed = true;
        if (event.IsAlt()) this.m_alt_pressed = true;
        event.SetCtrlPressed(this.m_ctrl_pressed);
        event.SetShiftPressed(this.m_shift_pressed);
        event.SetAltPressed(this.m_alt_pressed);
        if (focus_element && focus_element.OnKeyDown) {
            focus_element.OnKeyDown(event);
        }
    }

    OnKeyUp(key) {
        // key: e.g., 'a', 'Enter', 'ArrowUp', etc.
        // console.log("OnKeyUp", key);
        const event = new IEventKeyUp(key);
        const focus_element = this.GetFocusElement();
        if (event.IsCtrl()) this.m_ctrl_pressed = false;
        if (event.IsShift()) this.m_shift_pressed = false;
        if (event.IsAlt()) this.m_alt_pressed = false;
        event.SetCtrlPressed(this.m_ctrl_pressed);
        event.SetShiftPressed(this.m_shift_pressed);
        event.SetAltPressed(this.m_alt_pressed);
        if (focus_element && focus_element.OnKeyUp) {
            focus_element.OnKeyUp(event);
        }
    }

    OnTextInput(text) {
        // console.log("OnTextInput", text);
        const focus_element = this.GetFocusElement();
        if (focus_element && focus_element.OnTextInput) {
            focus_element.OnTextInput(text);
        }
    }

    GetElementByXY(x, y, e) {
        const root = this.GetRoot();
        const mouse_capture_element = this.GetMouseCaptureElement();
        if (mouse_capture_element) {
            return mouse_capture_element;
        }
        const element = root.GetElementByXY(x, y, e);
        return element || root;
    }

    SetClipboardText(text) { }
    GetClipboardText() { return ""; }

    // 加载字体
    async LoadFont(font_name, font_url) {
        try {
            // 创建 FontFace 对象
            const font = new FontFace(font_name, `url(${font_url})`);

            // 将字体添加到文档字体集合中
            document.fonts.add(font);

            // 等待字体加载完成
            await font.load();

            console.log(`Font ${font_name} loaded successfully.`);
            return font; // 返回字体对象，便于后续使用
        } catch (error) {
            console.error(`Failed to load font ${font_name}:`, error);
            throw error; // 重新抛出错误，让调用者可以处理
        }
    }

    StartTextInput() { }
    StopTextInput() { }
    SetTextInputRect(x, y, width, height) { }

}

class CanvasWindow extends IWindow {
    constructor(canvas, input) {
        super(new IPainter(canvas.getContext('2d')));
        this.m_canvas = canvas;
        this.m_input = input;

        // 添加以下两行代码使canvas可以接收焦点
        canvas.tabIndex = 0;  // 使canvas可以聚焦
        canvas.focus();       // 主动聚焦到canvas上

        this.OnSize(canvas.width, canvas.height);
        canvas.addEventListener('resize', (e) => {
            this.OnSize(canvas.width, canvas.height);
        });
        document.addEventListener('mousedown', (e) => {
            this.OnMouseDown(e.offsetX, e.offsetY, this.ConvertButton(e.button));
        });
        canvas.addEventListener('mousemove', (e) => {
            this.OnMouseMove(e.offsetX, e.offsetY);
        });
        canvas.addEventListener('mouseup', (e) => {
            this.OnMouseUp(e.offsetX, e.offsetY, this.ConvertButton(e.button));
        });
        canvas.addEventListener('wheel', (e) => {
            this.OnMouseWheel(e.deltaY);
        });
        // canvas 按键
        canvas.addEventListener('keydown', (e) => {
            this.OnKeyDown(GetKeyCode(e.keyCode));
        });
        canvas.addEventListener('keyup', (e) => {
            this.OnKeyUp(GetKeyCode(e.keyCode));
        });
        // input 按键
        input.addEventListener('keydown', (e) => {
            this.OnKeyDown(GetKeyCode(e.keyCode));
        });
        input.addEventListener('keyup', (e) => {
            this.OnKeyUp(GetKeyCode(e.keyCode));
        });
        // 输入法事件处理
        input.addEventListener('compositionstart', (event) => {
            this.m_input_composing = true;
            console.log('CompositionStart Event:', event.data);
        });
        input.addEventListener('compositionend', (event) => {
            this.m_input_composing = false;
            this.OnTextInput(event.data);
            console.log('CompositionEnd Event:', event.data);
        });
        input.addEventListener("input", (event) => {
            if (this.m_input_composing) {
                return;  // 输入法正在输入过程中，暂不处理
            }
            if (event.inputType === 'insertText') {
                // console.log('Input Event:', event.data);
                this.OnTextInput(event.data);
            } else {
                // console.log('Input Event:', event);
            }
        });

        input.addEventListener('blur', (e) => {
            // console.log('input blur', this.m_inputing);
            if (this.m_inputing) {
                input.focus();
            } else {
                input.value = "";
            }
        });

        input.addEventListener('focus', (e) => {
            // console.log('input focus', this.m_inputing);
            if (this.m_inputing) {
                input.value = "";
            } else {
                input.blur();
            }
        });
    }

    SetTextInputRect(x, y, w, h) {
        if (!this.m_inputing) return;
        this.m_input.style.left = x;
        this.m_input.style.top = y;
        this.m_input.style.width = w;
        this.m_input.style.height = h;
    }

    StartTextInput(view_bottom) {
        // console.log("StartTextInput", this.m_inputing);
        if (this.m_inputing) return;
        this.m_inputing = true;
        this.m_input_width = this.m_canvas.width;
        this.m_input_height = this.m_canvas.height;
        this.m_input_window_width = document.documentElement.clientWidth;
        this.m_input_window_height = document.documentElement.clientHeight;
        this.m_input_timestamp = new Date().getTime();
        this.m_input_view_bottom = (view_bottom || 0) / window.devicePixelRatio;

        this.m_input.focus();
    }

    StopTextInput() {
        // console.log("StopTextInput", this.m_inputing);
        if (!this.m_inputing) return;
        this.m_inputing = false;
        this.m_canvas.style.top = '0px';
        this.m_input.blur();
    }

    async SetClipboardText(text) {
        try {
            console.log('SetClipboardText', text);
            await navigator.clipboard.writeText(text);
            return true;
        }
        catch (e) {
            console.log(e);
            return false;
        }
    }

    async GetClipboardText() {
        try {
            const text = await navigator.clipboard.readText();
            console.log('GetClipboardText', text);
            return text;
        }
        catch (e) {
            console.log(e);
            return "";
        }
    }

    ConvertButton(button) {
        switch (button) {
            case 0:
                return MOUSE_BUTTON.LEFT;
            case 1:
                return MOUSE_BUTTON.MIDDLE;
            case 2:
                return MOUSE_BUTTON.RIGHT;
            default:
                return MOUSE_BUTTON.NONE;
        }
    }
}

export { IWindow, CanvasWindow };